#ifdef __linux__
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#else
#error "Not support non gnu/linux yet"
#endif // os deps

#include <cerrno>

#include "XM_Acceptor.hh"
#include "XM_Logger.hh"
#include "XM_InetAddress.hh"

// TODO: whose static field ...
static int createNonblocking()
{   // linux system socket
    int sockfd = ::socket(AF_INET, 
        SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
        IPPROTO_TCP
    );

    if (sockfd < 0) 
    LOG_FATAL("%s:%s:%d listen socket create err: %d\n",
        __FILE__, __FUNCTION__, __LINE__, errno
    );

    return sockfd;
}

XM_NAMESPACE_BEGIN

Acceptor::Acceptor(EvLoop* ev_loop, const InetAddr& listenAddr, bool reusePort)
: ev_loop__(ev_loop),
acceptSocket__(createNonblocking()),
acceptChannel__(ev_loop, acceptSocket__.fd()),
listening__(false)
{
    acceptSocket__.setReuseAddr(true);
    acceptSocket__.setReusePort(true);
    acceptSocket__.bindAddr(listenAddr);

    acceptChannel__.setReadCallback(
        std::bind(&Acceptor::fixRead, this)
    );
}

Acceptor::~Acceptor()
{
    acceptChannel__.disableAll();
    acceptChannel__.remove();
}

void Acceptor::fixRead()
{
    InetAddr peerAddr;
    int connfd = acceptSocket__.accept(&peerAddr);

    if (connfd >= 0)
    {
        if (newConnCallback__)
            newConnCallback__(connfd, peerAddr);
        else
            ::close(connfd);
    }
    else
    {
        LOG_ERROR("%s:%s:%d accept err: %d\n", __FILE__, __FUNCTION__, __LINE__, errno);
        if (errno == EMFILE)
        LOG_ERROR("%s:%s:%d sockfd reached limit\n", __FILE__, __FUNCTION__, __LINE__);
    }
}

XM_NAMESPACE_END